package com.bzframework.network.tcp;

import com.bzframework.network.DefaultNetworkType;
import com.bzframework.network.Network;
import com.bzframework.network.NetworkProvider;
import com.bzframework.network.NetworkType;
import io.vertx.core.Vertx;
import io.vertx.core.net.NetServer;
import io.vertx.core.parsetools.RecordParser;
import jakarta.annotation.Nonnull;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Component;

import java.net.InetSocketAddress;
import java.util.List;
import java.util.concurrent.CopyOnWriteArrayList;

/**
 * TcpNetworkProvider
 */
@Slf4j
@Component
@RequiredArgsConstructor
public class TcpNetworkProvider implements NetworkProvider<TcpServerProperties> {

    private final Vertx vertx;

    private static final List<Network> tcpNetworks = new CopyOnWriteArrayList<>();

    @Nonnull
    @Override
    public NetworkType getType() {
        return DefaultNetworkType.TCP_SERVER;
    }

    @Nonnull
    @Override
    public Network createNetwork(@Nonnull TcpServerProperties properties) {

        NetServer vertxNetServer = vertx.createNetServer();
        InetSocketAddress inetSocketAddress = properties.getInetSocketAddress();
        VertxTcpServer vertxTcpServer = new VertxTcpServer();

        NetServer netServer = vertxNetServer.connectHandler(netSocket -> {

            vertxTcpServer.register(netSocket);
            netSocket.handler(properties.getHandler());
            netSocket.exceptionHandler(e -> {
                log.error("receive data error: {}", e.getMessage(), e);
            });

            // 连接关闭处理
            netSocket.closeHandler(v -> {
                vertxTcpServer.remove(netSocket);
            });

        });
        netServer.listen(inetSocketAddress.getPort(), inetSocketAddress.getHostString())
                .onComplete(result -> {
                    if (result.succeeded()) {
                        log.info("tcp server is start: {}", inetSocketAddress.getAddress());
                    }
                    if (result.failed()) {
                        log.error("tcp server is start error: {}", inetSocketAddress.getAddress(), result.cause());
                    }
                });

        tcpNetworks.add(vertxTcpServer);
        return vertxTcpServer;
    }

    @Override
    public void shutdown() {
        tcpNetworks.forEach(Network::shutdown);
    }
}
